﻿using api_identity.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace api_identity.Handlers.AuthorizationHandlers
{
    public class RolePermissionsHandler : AuthorizationHandler<RolePermissionsRequirement>
    {
        private readonly ApplicationDbContext _context;
        private readonly ILogger<RolePermissionsHandler> _logger;

        public RolePermissionsHandler(ApplicationDbContext context, ILogger<RolePermissionsHandler> logger)
        {
            this._context = context;
            this._logger = logger;
        }

        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RolePermissionsRequirement requirement)
        {
            if (!context.User.Identity.IsAuthenticated || !(context.Resource is Microsoft.AspNetCore.Routing.RouteEndpoint route))
            {
                context.Fail();
                return;
            }

            var rIdClaims = context.User.Claims.Where(c => c.Type == "rid");
            if (rIdClaims == null || rIdClaims.Count() == 0)
            {
                context.Fail();
                return;
            }

            if (await Handle(route, rIdClaims.Select(c => c.Value)))
            {
                context.Succeed(requirement);
                return;
            }

            context.Fail();
        }

        private async Task<bool> Handle(Microsoft.AspNetCore.Routing.RouteEndpoint route, IEnumerable<string> rIds)
        {
            this._logger.LogDebug($"{route.RoutePattern.RawText}");

            if (!route.RoutePattern.Defaults.TryGetValue("action", out object action) || !route.RoutePattern.Defaults.TryGetValue("controller", out object controller))
            {
                return false;
            }

            var flag = await (from p in this._context.Permissions
                              join rp in this._context.RolePermissions
                              on p.Id equals rp.PermissionsId
                              where rIds.Contains(rp.RoleId)
                              && p.ActionName == action.ToString()
                              && p.ControllerName == controller.ToString()
                              select p).AnyAsync();

            return flag;
        }

    }
}
